home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!mcnc!gatech!bloom-beacon!husc6!necntc!ncoast!allbery
- From: jv@mh.nl.UUCP (Johan Vromans)
- Newsgroups: comp.sources.misc
- Subject: v03i019: Sendmail replacement for smail sites
- Keywords: mail sendmail smail smtp tcp-ip
- Message-ID: <1863@mhres.mh.nl>
- Date: 16 May 88 15:24:17 GMT
- Sender: allbery@ncoast.UUCP
- Reply-To: jv@mh.nl.UUCP (Johan Vromans)
- Organization: Multihouse NV, the Netherlands
- Lines: 2701
- Approved: allbery@ncoast.UUCP
-
- comp.sources.misc: Volume 3, Issue 19
- Submitted-By: "Johan Vromans" <jv@mh.nl.UUCP>
- Archive-Name: sm-smtp
-
- Lots of people asked me for this, so here it is ...
-
- This is a merger of Ian's standalone talker and MIT's talker.
- Peter Honeyman hacked on it to make it work correctly on the Arpanet.
-
- Adapted by Johan Vromans <jv@mh.nl>, May 1988
-
- - simplified code
-
- - adapted to System V (Most notably: HP-UX)
-
- - added better host/domain name handling & setup
-
- - added time-routine (from smail)
-
- - added "config.h" for local settings, and moved common includes and
- portability code to "smtp.h"
-
- - produces a "smtpd" to be used under inetd, "sa-smtpd" (standalone) and
- "smtp" interface program.
-
- #---------------- cut here ----------------
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # Makefile
- # README
- # cmds.h
- # config.h
- # converse.c
- # dconverse.c
- # misc.c
- # miscerrs.h
- # mx.c
- # netio.c
- # smtp.8
- # smtp.c
- # smtp.h
- # smtpd.c
- # sysexits.h
- # syslog.h
- # MANIFEST
- # This archive created: Mon May 16 17:16:19 1988
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'Makefile'" '(800 characters)'
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- sed 's/^X//' << \SHAR_EOF > 'Makefile'
- X#!/bin/make
- X
- XCFLAGS = -O
- XLIBS = -lBSD -lbsdipc -lsyslog # HP-UX
- X#LIBS = # BSD
- X
- Xall: smtp smtpd
- X
- XSTD = netio.o misc.o
- X
- Xsmtp: smtp.o converse.o $(STD)
- X $(CC) $(CFLAGS) -o smtp smtp.o converse.o $(STD) $(LIBS)
- X
- Xsmtpd: smtpd.o dconverse.o $(STD)
- X $(CC) $(CFLAGS) -o smtpd smtpd.o dconverse.o $(STD) $(LIBS)
- X
- Xsa-smtpd: sa-smtpd.o dconverse.o $(STD)
- X $(CC) $(CFLAGS) -o sa-smtpd sa-smtpd.o dconverse.o $(STD) $(LIBS)
- X
- Xsmptd.o sa-smtpd.o smtp.o $(STD) converse.o: smtp.h
- X
- Xsmtp.h: config.h miscerrs.h
- X -touch smtp.h
- X
- Xsmtpd.o: smtpd.c
- X $(CC) -c $(CFLAGS) -DINETD smtpd.c
- X
- Xsa-smtpd.o: smtpd.c
- X $(CC) -c $(CFLAGS) -UINETD smtpd.c
- X mv smtpd.o sa-smtpd.o
- X
- Xclean:
- X rm -f smtp smtpd sa-smtpd *.o
- X
- Xlint:
- X lint smtp.c netio.c converse.c
- X lint smtpd.c netio.c dconverse.c
- X lint -DINETD smtpd.c netio.c dconverse.c
- X
- SHAR_EOF
- if test 800 -ne "`wc -c < 'Makefile'`"
- then
- echo shar: "error transmitting 'Makefile'" '(should have been 800 characters)'
- fi
- fi
- echo shar: "extracting 'README'" '(2322 characters)'
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- sed 's/^X//' << \SHAR_EOF > 'README'
- XThis is a merger of Ian's standalone talker and MIT's talker.
- XPeter Honeyman hacked on it to make it work correctly on the Arpanet.
- X
- XAdapted by Johan Vromans <jv@mh.nl>, May 1988
- X
- X - simplified code
- X
- X - adapted to System V (Most notably: HP-UX)
- X
- X - added better host/domain name handling & setup
- X
- X - added time-routine (from smail)
- X
- X - added "config.h" for local settings, and moved common includes and
- X portability code to "smtp.h"
- X
- X - produces a "smtpd" to be used under inetd, "sa-smtpd" (standalone) and
- X "smtp" interface program.
- X
- XDisclaimers: it works for me. I didn't test "sa-smtpd", nor tried it under
- XBerkeley Unix. However, the code originated from BSD, and I tried to keep
- Xsystem dependent things intact.
- XI did not look at the "mx" program which is also included.
- X
- XHow I use it
- X------------
- XI use a mail system based on smail 2.5.
- X
- XMy user agents can be Elm, mail or mailx, and pass the message to smail for
- Xaliasing and routing. Smail hands the message to either a localmail program
- X(for local delivery: user mailboxes, programs or files) or a remotemail
- Xprogram (for remote delivery: uucp or smtp).
- X
- XIn the routing database, all hosts I can connect to are considered
- X"UUCP"-hosts, and delivery is passed to a shell script. In this script,
- Xhosts are looked-up in the file /etc/hosts.smtp (with the names of TCP/IP
- Xhosts which speak smtp) and - if found - delivery is passed to the smtp
- Xprogram.
- X
- XOtherwise delivery is passed to uux as usual.
- X
- XOn the input side, smtp mail is caught by the smtpd program, and passed to
- Xsmail for further processing.
- X
- XWhy I don't use sendmail
- X------------------------
- XUsing sendmail has a few drawbacks:
- X
- X - it is hard to configure and difficult to maintain
- X
- X - lots of the functionality of sendmail is also in smail. Who is aliasing,
- X who is routing, who is bouncing?
- X
- X - I cannot prevent sendmail from rewriting message headers
- X
- X - when something goes wrong, sendmail will try to do sensible things
- X which bypass the rest of the mail system
- X
- XSmail does everything I want, except for the SMTP delivery. Well - the
- Xprograms included do just that.
- X
- XAnd last but not least: it is more easy to maintain a few small, well
- Xdocumented and easy to understand programs than one big hard to understand/
- Xconfigure/maintain program.
- X
- XMay 1988, Johan Vromans, Multihouse Research
- SHAR_EOF
- if test 2322 -ne "`wc -c < 'README'`"
- then
- echo shar: "error transmitting 'README'" '(should have been 2322 characters)'
- fi
- fi
- echo shar: "extracting 'cmds.h'" '(1024 characters)'
- if test -f 'cmds.h'
- then
- echo shar: "will not over-write existing file 'cmds.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'cmds.h'
- X#ifndef lint
- Xstatic char *cmds_sccsid = "@(#)cmds.h 1.5 87/04/06";
- X#endif lint
- X/* cmds.h */
- X
- X/* Copyright 1984 by the Massachusetts Institute of Technology */
- X/* See permission and disclaimer notice in file "notice.h" */
- X
- X/* EMACS_MODES: c !fill */
- X
- X/*
- X * smtp command strings and associated codes. Note that the command code
- X * MUST be equal to the index of the command in the table.
- X */
- X
- X
- Xstruct cmdtab {
- X char *c_name; /* command name */
- X int c_len; /* command length */
- X} cmdtab[] = {
- X#define NONE 0 /* no such command */
- X { "", 0, },
- X#define HELO 1
- X { "HELO", 4, },
- X#define MAIL 2
- X { "MAIL FROM:", 10 },
- X#define RCPT 3
- X { "RCPT TO:", 8, },
- X#define DATA 4
- X { "DATA", 4, },
- X#define QUIT 5
- X { "QUIT", 4, },
- X#define RSET 6
- X { "RSET", 4, },
- X#define NOOP 7
- X { "NOOP", 4, },
- X#define VRFY 8
- X { "VRFY", 4, },
- X/* sendmail compatibility */
- X#define ONEX 9
- X { "ONEX", 4, },
- X#define VERB 10
- X { "VERB", 4, },
- X
- X { 0, 0, } /* end of table marker */
- X};
- X
- X#define toupper(c) (islower(c) ? ((c) - ('a' - 'A')) : (c))
- SHAR_EOF
- if test 1024 -ne "`wc -c < 'cmds.h'`"
- then
- echo shar: "error transmitting 'cmds.h'" '(should have been 1024 characters)'
- fi
- fi
- echo shar: "extracting 'config.h'" '(1280 characters)'
- if test -f 'config.h'
- then
- echo shar: "will not over-write existing file 'config.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'config.h'
- X/* config.h for smtp package */
- X
- X/*
- X * define either BSD or SYSV.
- X */
- X#define SYSV /* SystemV with TCP/IP */
- X/* # define BSD /* Berkeley 4.[23] */
- X
- X/*
- X * If set, HOSTDOMAIN overrides HOSTNAME and MYDOM.
- X */
- X/* #define HOSTDOMAIN "mhres.mh.nl" */
- X
- X/*
- X * If not set, HOSTNAME will be fetched using uname (SYSV) or gethostname (BSD)
- X */
- X/* #define HOSTNAME "mhres" */
- X
- X/*
- X * If set, MYDOM will be appended to the host name.
- X */
- X#define MYDOM ".mh.nl"
- X
- X/*
- X * Define server to use. Defaults to "smtp".
- X */
- X/* #define SERVNAME "tsmtp" */
- X
- X/*
- X * Define SYSLOG when the syslog rotuine can be used. For SYSV, it will
- X * use a PD syslog package.
- X */
- X#define SYSLOG
- X
- X/*
- X * Define this if you want a log of mail transactions. See the code in
- X * smtpd.c.
- X */
- X#define SIMPLELOG
- X
- X/*
- X * The mailer used to send the mail.
- X */
- X#define MAILER "/bin/smail"
- X
- X/*
- X * Define HOOTING for printout of transaction (needed for "Transaction
- X * of session")
- X * Used by "netio" in "smtp"
- X */
- X#define HOOTING
- X
- X/*
- X * Define NOSYSEXITS iy you don't have <sysexits.h> (or "sysexits.h" on SYSV.
- X */
- X
- X/* define NOSYSEXITS */
- X
- X/*
- X * Define this if your signal(2) takes a void function as its second arg.
- X * Otherwise leave it empty
- X */
- X
- X/* define TYPESIG ((void)(*)()) */
- X#ifndef TYPESIG
- X# define TYPESIG
- X#endif
- X
- SHAR_EOF
- if test 1280 -ne "`wc -c < 'config.h'`"
- then
- echo shar: "error transmitting 'config.h'" '(should have been 1280 characters)'
- fi
- fi
- echo shar: "extracting 'converse.c'" '(4950 characters)'
- if test -f 'converse.c'
- then
- echo shar: "will not over-write existing file 'converse.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'converse.c'
- X/*
- X * Do the necessary commands for a smtp transfer. Start by waiting for the
- X * connection to open, then send HELO, MAIL, RCPT, and DATA. Check the
- X * reply codes and give up if needed.
- X *
- X * This code modified from the MIT UNIX TCP implementation:
- X * Copyright 1984 Massachusetts Institute of Technology
- X *
- X * Permission to use, copy, modify, and distribute this file
- X * for any purpose and without fee is hereby granted, provided
- X * that this copyright and permission notice appear on all copies
- X * and supporting documentation, the name of M.I.T. not be used
- X * in advertising or publicity pertaining to distribution of the
- X * program without specific prior permission, and notice be given
- X * in supporting documentation that copying and distribution is
- X * by permission of M.I.T. M.I.T. makes no representations about
- X * the suitability of this software for any purpose. It is provided
- X * "as is" without express or implied warranty.
- X */
- X
- X#include "smtp.h"
- X#include <signal.h>
- X
- X#define MAXTIME (60 * 5) /* way too long - die */
- X
- Xint success, termcode;
- X
- Xint gethostname();
- Xextern int death();
- Xchar *strcat(), *strcpy();
- Xextern char hostname[], hostdomain[];
- X
- Xconverse(from, rcpt, sfi, sfo, mlfd)
- Xchar *from; /* from address */
- Xchar *rcpt; /* to address */
- XFILE *sfi; /* smtp input */
- XFILE *sfo; /* smtp output */
- XFILE *mlfd; /* mail file descriptor */
- X{
- X extern expect();
- X extern char *sendhost;
- X char buf[MAXSTR];
- X char host[64];
- X
- X (void) signal(SIGALRM, TYPESIG death);
- X (void) alarm(MAXTIME); /* make sure we eventually go away */
- X
- X expect(220, sfi, sfo); /* expect a service ready msg */
- X/* (void) gethostname(host, sizeof host); */
- X
- X if (sendhost == NULL)
- X (void) sprintf(buf, "HELO %s.%s\n", hostdomain);
- X else
- X (void) sprintf(buf, "HELO %s\n", sendhost);
- X tputs(buf, sfo);
- X expect(250, sfi, sfo); /* expect an OK */
- X
- X (void) strcpy(buf, "MAIL FROM:<");
- X (void) strcat(buf, from);
- X (void) strcat(buf, ">\n");
- X tputs(buf, sfo);
- X expect(250, sfi, sfo); /* expect OK */
- X
- X (void) strcpy(buf, "RCPT TO:<");
- X (void) strcat(buf, rcpt);
- X (void) strcat(buf, ">\n");
- X tputs(buf, sfo);
- X expect(250, sfi, sfo); /* expect OK */
- X
- X tputs("DATA\n", sfo);
- X expect(354, sfi, sfo);
- X do_data(mlfd, sfo);
- X expect(250, sfi, sfo); /* hope data is OK */
- X success = TRUE;
- X
- X tputs("QUIT\n", sfo);
- X /*expect(221, sfi, sfo);*/ /* who cares? */
- X}
- X
- X
- X/*
- X * Send the data from the specified mail file out on the current smtp
- X * connection. Do the appropriate netascii conversion and starting '.'
- X * padding. Send the <CRLF>.<CRLF> at completion.
- X */
- Xdo_data(fd, sfo)
- Xregister FILE *fd; /* mail file descriptor */
- XFILE *sfo; /* smtp files */
- X{
- X register int c; /* current character */
- X int nlseen = FALSE; /* newline */
- X extern int debug;
- X
- X if (debug)
- X (void) printf("in do_data\n");
- X while ((c = getc(fd)) != EOF) {
- X if (nlseen) {
- X nlseen = FALSE;
- X if (c == '.')
- X (void) putc('.', sfo);
- X }
- X if (c == '\n') {
- X (void) putc('\r', sfo);
- X nlseen = TRUE;
- X }
- X (void) putc(c, sfo);
- X#ifdef what_the_fuck_is_all_this_about
- X if (c == '\r')
- X (void) putc('\0', sfo);
- X#endif
- X }
- X if (!nlseen) {
- X (void) putc('\r', sfo);
- X (void) putc('\n', sfo);
- X }
- X#ifdef this_is_bullshit_too
- X (void) putc('\n', sfo); /* TODO: why is this line needed? */
- X#endif
- X (void) putc('.', sfo);
- X (void) putc('\r', sfo);
- X (void) putc('\n', sfo);
- X (void) fflush(sfo);
- X if (ferror(sfo)) {
- X perror("write error in smtp");
- X bomb(E_IOERR);
- X }
- X if (debug)
- X (void) printf("leaving do_data\n");
- X}
- X
- X
- X/*
- X * Expect a reply message with the specified code. If the specified code
- X * is received return TRUE; otherwise print the error message out on the
- X * standard output and give up. Note that the reply can be a multiline
- X * message.
- X */
- Xexpect(code, sfi, sfo)
- Xint code;
- XFILE *sfi, *sfo;
- X{
- X int retcd;
- X char cmdbuf[MAXSTR], termbuf[MAXSTR];
- X extern int debug;
- X
- X if (debug)
- X (void) fprintf(stderr, "expect %d ", code);
- X for (;;) { /* get whole reply */
- X if (tgets(cmdbuf, sizeof cmdbuf, sfi) > 0) { /* get input line */
- X if (cmdbuf[3] == '-') /* continuation line? */
- X continue;
- X /* no, last line */
- X if (sscanf(cmdbuf, "%d", &retcd) !=1 ){
- X (void) fprintf(stderr,
- X "non-numeric command reply!\n");
- X bomb(E_IOERR);
- X }
- X if (retcd == code) {
- X if (debug)
- X (void) fprintf(stderr," got it\n");
- X return;
- X }
- X else {
- X if (debug)
- X (void) fprintf(stderr,
- X " FAIL (got %d)\n", retcd);
- X /* return the error line */
- X (void) strcpy(termbuf, cmdbuf);
- X tputs ("QUIT\n", sfo);
- X break;
- X }
- X }
- X else if (success)
- X (void) strcpy(termbuf, "250 OK\n");
- X else {
- X (void) perror("smtp");
- X bomb(451);
- X }
- X }
- X termcode = !success; /* error return */
- X if (debug)
- X (void) fprintf(stderr, " FALLOUT\n");
- X bomb(retcd); /* map smtp errors to mailsys errors */
- X}
- X
- X/* Maximum time to live elapsed. Die right now. */
- Xdeath()
- X{
- X (void) fprintf(stderr, "Max transfer length timeout.\n");
- X (void) exit(1);
- X}
- SHAR_EOF
- if test 4950 -ne "`wc -c < 'converse.c'`"
- then
- echo shar: "error transmitting 'converse.c'" '(should have been 4950 characters)'
- fi
- fi
- echo shar: "extracting 'dconverse.c'" '(12608 characters)'
- if test -f 'dconverse.c'
- then
- echo shar: "will not over-write existing file 'dconverse.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'dconverse.c'
- X#ifndef lint
- Xstatic char *sccsid = "@(#)converse.c 1.8 87/05/14";
- X#endif lint
- X/* Copyright 1984 Massachusetts Institute of Technology
- X
- XPermission to use, copy, modify, and distribute this program
- Xfor any purpose and without fee is hereby granted, provided
- Xthat this copyright and permission notice appear on all copies
- Xand supporting documentation, the name of M.I.T. not be used
- Xin advertising or publicity pertaining to distribution of the
- Xprogram without specific prior permission, and notice be given
- Xin supporting documentation that copying and distribution is
- Xby permission of M.I.T. M.I.T. makes no representations about
- Xthe suitability of this software for any purpose. It is pro-
- Xvided "as is" without express or implied warranty. */
- X
- X/*
- X * smtpd - World's most trivial SMTP server. Only accepts the MAIL, FROM,
- X * RCPT, and DATA commands. Generates a date file for the mail
- X * daemon and kicks the mail daemon off.
- X */
- X
- X#include "smtp.h"
- X
- X#ifdef BSD
- X#include <sgtty.h>
- X#endif
- X/* #include <ioctl.h> */
- X#include <signal.h>
- X#include <sys/uio.h>
- X#include <sys/socket.h>
- X#include <netinet/in.h>
- X
- X#include "cmds.h"
- X
- X/* tunable constants */
- X
- X#define SECONDS 1
- X#define MINUTES 60
- X#define HOURS (60 * MINUTES)
- X
- X#define SHORTTIME (5 * MINUTES) /* enough time for easy stuff */
- X#define LONGTIME (2 * HOURS) /* max time, DATA to `.' */
- X
- X#define DATAMODE 0660 /* mode for data file */
- X
- X#ifdef MAILER
- Xchar *sigmaild = MAILER;
- X#else
- Xchar *sigmaild = "/bin/rmail";
- X#endif
- X
- Xtypedef long in_name; /* internet host address */
- X
- Xint buflen; /* size of string in cmd buffer */
- X
- Xstatic char rcptlist[MAXSTR]; /* recipient list */
- Xstatic char *rcptlast; /* end of rcptlist */
- X
- XFILE *datafd; /* data file descriptor */
- X
- Xchar dataname[NAMSIZ]; /* data file name */
- X
- Xtypedef int event;
- X
- Xextern int death();
- Xextern int alarmtr();
- X
- Xextern char *strcpy();
- Xextern char *index();
- Xextern char *rindex();
- Xextern char *strcpy(), *strcat();
- X
- Xextern char hostdomain[];
- Xextern char hostname[];
- Xextern char arpanows[];
- X
- X#ifdef SIMPLELOG
- X#include <sys/file.h>
- Xstatic char mailfrom[MAXSTR], rcptto[MAXSTR];
- X#endif
- X
- X/*
- X * This is the routine which processes incoming smtp commands from the
- X * user. It goes to sleep awaiting network input. When a complete
- X * command is received, the tcp receiver task awakens us to process it.
- X * Currently only the commands listed in the command table are accepted.
- X * This routine never returns.
- X */
- X/* ARGSUSED from */
- Xconverse(fi, fo, from)
- XFILE *fi, *fo;
- Xstruct sockaddr_in *from;
- X{
- X char greeting[MAXSTR];
- X
- X (void) chdir("/tmp"); /* put temp files somewhere sensible */
- X (void) signal(SIGALRM, TYPESIG alarmtr);
- X (void) alarm(SHORTTIME); /* make sure we eventually go away */
- X setdates ();
- X (void) sprintf(greeting, "220 %s SMTP server ready at %s\n",
- X hostdomain, arpanows);
- X (void) tputs(greeting, fo);
- X do_helo(fi, fo); /* wait for the hello */
- X for (;;) { /* until QUIT */
- X do_mail(fi, fo); /* wait for the mail command */
- X while (do_rcpt(fi, fo)) /* do all the recipients */
- X ;
- X (void) alarm(LONGTIME);
- X do_data(fi, fo); /* do the data */
- X }
- X}
- X
- X/*
- X * Wait for the user to send the HELO command. Punt out if he sends
- X * QUIT or RSET.
- X */
- Xdo_helo(fi, fo)
- XFILE *fi, *fo;
- X{
- X char cmdbuf[MAXSTR];
- X char greeting[MAXSTR];
- X
- X for (;;) { /* until HELO, QUIT, or RSET */
- X buflen = tgets(cmdbuf, sizeof cmdbuf, fi); /* wait for command */
- X switch (cmdparse(cmdbuf, buflen)) {
- X case QUIT:
- X case RSET:
- X quit(fi, fo);
- X case NOOP:
- X (void) tputs("250 OK\n", fo);
- X continue;
- X case HELO:
- X (void) sprintf(greeting, "250 %s Pleased to meet you\n", hostname);
- X (void) tputs(greeting, fo);
- X return;
- X case NONE:
- X bitch(cmdbuf, fo);
- X continue;
- X default:
- X (void) tputs("503 Expecting HELO\n", fo);
- X continue;
- X }
- X }
- X}
- X
- X/*
- X * Wait for the user to send the MAIL command. Punt out if he sends
- X * QUIT or RSET.
- X */
- Xdo_mail(fi, fo)
- XFILE *fi, *fo;
- X{
- X char cmdbuf[MAXSTR];
- X
- X for (;;) { /* until MAIL, QUIT, or RSET */
- X buflen = tgets(cmdbuf, sizeof cmdbuf, fi); /* wait for command */
- X switch (cmdparse(cmdbuf, buflen)) {
- X case QUIT:
- X case RSET:
- X quit(fi, fo);
- X case NOOP:
- X (void) tputs("250 OK\n", fo);
- X continue;
- X case MAIL:
- X#ifdef SIMPLELOG
- X strcpy(mailfrom, cmdbuf);
- X#endif
- X (void) tputs("250 OK\n", fo);
- X return;
- X case NONE:
- X bitch(cmdbuf, fo);
- X continue;
- X default:
- X (void) tputs("503 Expecting MAIL\n", fo);
- X continue;
- X }
- X }
- X}
- X
- X/*
- X * Wait for the user to send the RCPT command. Punt out if he sends
- X * QUIT or RSET. Returns TRUE if a RCPT command was received, FALSE
- X * if a DATA command was received.
- X */
- Xdo_rcpt(fi, fo)
- XFILE *fi, *fo;
- X{
- X char cmdbuf[MAXSTR];
- X
- X for (;;) { /* until RCPT, DATA, QUIT, or RSET */
- X buflen = tgets(cmdbuf, sizeof cmdbuf, fi); /* wait for command */
- X switch (cmdparse(cmdbuf, buflen)) {
- X case QUIT:
- X case RSET:
- X quit(fi, fo);
- X case NOOP:
- X (void) tputs("250 OK\n", fo);
- X continue;
- X case RCPT:
- X#ifdef SIMPLELOG
- X strcat(rcptto, cmdbuf);
- X#endif
- X if (!parse_rcpt(cmdbuf, buflen)) {
- X (void) tputs("501 Syntax error in recipient name\n", fo);
- X continue;
- X }
- X (void) tputs("250 OK\n", fo);
- X return(TRUE);
- X case DATA:
- X if (*rcptlist == 0) {
- X (void) tputs("503 Expecting RCPT\n", fo);
- X continue;
- X }
- X if (!init_xfr()) { /* set up data file */
- X (void) tputs("451 Can't initialize transfer\n", fo);
- X death(E_CANTOPEN);
- X }
- X (void) tputs("354 Start mail input; end with <CRLF>.<CRLF>\n", fo);
- X return(FALSE);
- X case NONE:
- X bitch(cmdbuf, fo);
- X continue;
- X default:
- X (void) tputs("503 Expecting RCPT or DATA\n", fo);
- X continue;
- X }
- X }
- X}
- X
- Xdo_data(fi, fo)
- XFILE *fi, *fo;
- X{
- X char cmd[MAXSTR];
- X register char *buf = cmd;
- X int sysret;
- X
- X setdates ();
- X fprintf (datafd, "Received: by %s with SMTP; %s\n",
- X hostdomain, arpanows);
- X for (;;) {
- X if (tgets(buf, sizeof cmd, fi) < 0)
- X death(E_IOERR);
- X if (*buf == '.') {
- X buf++; /* hidden dot */
- X if (*buf == '\n')
- X break;
- X }
- X (void) fputs(buf, datafd);
- X }
- X
- X (void) fclose(datafd);
- X
- X /* run mailer with rcptlist as args and message as input */
- X /* TODO: check system status to see if OK */
- X (void) sprintf(cmd, "%s %s <%s", sigmaild, rcptlist, dataname);
- X sysret = system(cmd);
- X if (sysret == 0)
- X (void) tputs("250 OK\n", fo);
- X else
- X (void) tputs("554 Transaction failed\n", fo);
- X
- X#ifdef SIMPLELOG
- X simplelog(abs(sysret));
- X#endif
- X
- X /* shouldn't leave it around, but ... */
- X if (sysret == 0)
- X (void) unlink(dataname); /* remove temporaries */
- X
- X *dataname = *rcptlist = *rcptto = 0;
- X rcptlast = 0;
- X}
- X
- X/*
- X * Create the data file for the transfer. Get unique
- X * names and create the files.
- X */
- Xinit_xfr()
- X{
- X int dfd; /* file desc. for data file */
- X
- X (void) tmpnam(dataname);
- X
- X if ((dfd = creat(dataname, DATAMODE)) < 0)
- X return FALSE;
- X datafd = fdopen(dfd, "w"); /* make stdio descriptor */
- X if (datafd == NULL)
- X return FALSE;
- X
- X
- X return TRUE;
- X}
- X
- X/*
- X * Give up on the transfer. Unlink the data file (if any),
- X * close the tcp connection, and exit.
- X */
- Xquit(fi, fo)
- XFILE *fi, *fo;
- X{
- X char greeting[MAXSTR];
- X
- X (void) sprintf(greeting, "221 %s Terminating\n", hostname);
- X (void) tputs(greeting, fo);
- X (void) fclose(fi);
- X (void) fclose(fo);
- X exit(0);
- X}
- X
- X/*
- X * Parse the command part off the specified buffer. Return the index
- X * of the command in the command table(or 0 if the command is not
- X * recognized).
- X * The commands and indices accepted are listed in the include file
- X * "cmds.h".
- X */
- Xcmdparse(buf, len)
- Xchar *buf;
- Xint len;
- X{
- X register char *cmdp, *bufp; /* command, buffer ptrs. */
- X register struct cmdtab *ct; /* cmd table ptr */
- X register int i; /* index in cmd table */
- X int clen; /* length of this command */
- X
- X for (ct = &cmdtab[1], i = 1; ct->c_name != NULL; ct++, i++) {
- X clen = ct->c_len;
- X if (len < clen) /* buffer shorter than command? */
- X continue;
- X /* case-insensitive matching of command names */
- X for (cmdp = ct->c_name, bufp = buf;
- X clen > 0 && *cmdp == toupper(*bufp);
- X cmdp++, bufp++, clen--)
- X ;
- X if (clen == 0) { /* success */
- X /* sendmail compatibility */
- X if (i == ONEX || i == VERB)
- X i = NOOP;
- X return i;
- X }
- X }
- X return 0;
- X}
- X
- Xstatic char *to; /* ptr. into request buffer */
- X
- X/*
- X * Parse the recipient spec in the buffer. Start by stripping the
- X * command off the front of the buffer. Then call canon() to convert
- X * the recpient name into a format acceptable to the mailer daemon
- X * (ie. the original multiple-at-sign format).
- X * Returns TRUE if parsed successfully, FALSE otherwise.
- X */
- X/* ARGSUSED len */
- Xparse_rcpt(buf, len)
- Xchar *buf; /* command buffer */
- Xint len; /* size of buffer string */
- X{
- X register char *from; /* ptr to recipient name */
- X char *end;
- X
- X from = &buf[cmdtab[RCPT].c_len];
- X while (*from == ' ' || *from == '\t')
- X from++;
- X if (*from == '<') {
- X end = index(from++, '>');
- X if (end == 0) {
- X (void) printf("no > at end of string\n");
- X return FALSE;
- X }
- X *end = 0;
- X }
- X if (rcptlast) {
- X rcptlast += strlen(rcptlast);
- X *rcptlast++ = ' ';
- X } else
- X rcptlast = rcptlist;
- X /* NB: we use the canonical name even if `bad' */
- X if (canon(from, rcptlast)) /* canonicalize */
- X#ifdef DEBUG
- X (void) printf("parsed ok: %s\n", rcptlast);
- X else
- X (void) printf("parsed bad: %s\n", rcptlast);
- X#endif
- X ;
- X return TRUE;
- X}
- X
- X/*
- X * Canonicalize the smtp-style path pointed to by from into the buffer
- X * pointed to by the external static variable to. The result will be
- X * a string containing the multiple-at-sign form, as desired by the
- X * mailer daemon. Also removes the '\' escape characters.
- X * The procedure follwed is recursive: this routine is recursively
- X * called for each "@host" in the from string.
- X * Returns TRUE if successful, or FALSE if the format of the recipient
- X * name is bad.
- X */
- Xrcanon(from)
- Xregister char *from; /* start of string to canonicalize */
- X{
- X register char *end; /* end of this part of path */
- X register int escseen; /* escape character seen */
- X int atseen; /* '@' seen in mailbox */
- X
- X escseen = atseen = FALSE;
- X if (*from == '@') { /* host name; find end */
- X for (end = from; *end != '\0'; end++) {
- X if (escseen)
- X escseen = FALSE;
- X else if (*end == '\\') /* escape? */
- X escseen = TRUE;
- X else if (*end == ',' || *end == ':')
- X break;
- X }
- X if (*end == '\0' || !rcanon(end+1)) { /* bad format? */
- X#ifdef PICKY /*{*/
- X (void) printf("no mailbox found\n");
- X return FALSE;
- X } else
- X#else
- X }
- X#endif /* PICKY */
- X {
- X escseen = FALSE;
- X for (*from = '%'; from < end; from++) { /* copy into to buffer */
- X if (escseen)
- X escseen = FALSE;
- X else if (*from == '\\') {
- X escseen = TRUE;
- X continue;
- X }
- X *to++ = *from;
- X }
- X *to = '\0';
- X return TRUE;
- X }
- X } else {
- X for (; *from; from++) { /* copy mailbox */
- X if (escseen)
- X escseen = FALSE;
- X else if (*from == '\\') {
- X escseen = TRUE;
- X continue;
- X } else if (*from == '@') { /* end of username? */
- X (void) printf("found @ in mailbox\n");
- X *from = '%';
- X atseen = TRUE;
- X }
- X *to++ = *from;
- X }
- X *to = 0;
- X return atseen;
- X }
- X}
- X
- X/* Time to live elapsed or io error. */
- Xdeath(weapon)
- X{
- X#ifdef SIMPLELOG
- X simplelog(weapon);
- X#endif
- X (void) printf("Time to die.\n");
- X /*(void) unlink(dataname);*/
- X exit(1);
- X}
- X
- Xalarmtr()
- X{
- X death(E_TEMPFAIL);
- X}
- X
- Xcanon(in, out)
- Xchar *in, *out;
- X{
- X char *at;
- X
- X to = out;
- X if (funnychars(in) || !rcanon(in) || (at = rindex(out, '%')) == 0)
- X return(FALSE);
- X *at = '@';
- X return TRUE;
- X}
- X
- Xfunnychars(str)
- Xregister char *str;
- X{
- X
- X for (;;)
- X switch(*str++) {
- X case '^':
- X case '&':
- X case '>':
- X case '<':
- X case '`':
- X case '|':
- X case ';':
- X case '\'':
- X return TRUE;
- X
- X case 0:
- X return FALSE;
- X }
- X}
- X
- X#ifdef SIMPLELOG
- Xsimplelog(retcode)
- X{
- X char buf[1024], *bptr, *status;
- X int fd;
- X time_t t;
- X extern char *ctime();
- X extern time_t time();
- X
- X t = time(&t);
- X switch (retcode) {
- X case E_CANTOPEN:
- X status = "OPEN FAILED";
- X break;
- X case E_IOERR:
- X status = "IO ERROR";
- X break;
- X case E_TEMPFAIL:
- X status = "TIMED OUT";
- X break;
- X case 0:
- X status = "OK";
- X break;
- X default:
- X status = "DELIVERY FAILURE";
- X break;
- X }
- X if (*mailfrom == 0)
- X strcpy(mailfrom, "UNKNOWN");
- X if (*rcptto == 0)
- X strcpy(rcptto, "UNKNOWN");
- X (void) sprintf(buf, "%s %s %s %s", mailfrom, rcptto, status, ctime(&t));
- X for (bptr = buf; *bptr; bptr++)
- X if (*bptr == '\n' || *bptr == '\r')
- X *bptr = ' ';
- X strcat(bptr, "\n");
- X if ((fd = open("/tmp/smtpd.log", O_WRONLY|O_APPEND)) >= 0) {
- X (void) write(fd, buf, strlen(buf));
- X (void) close(fd);
- X }
- X}
- X#endif
- X
- Xbitch(buf, fo)
- Xchar *buf;
- XFILE *fo;
- X{
- X char gripe[MAXSTR], *nlptr;
- X
- X if ((nlptr = index(buf, '\n')) != 0)
- X *nlptr = 0;
- X (void) sprintf(gripe, "502 %s ... Not recognized\n", buf);
- X (void) tputs(gripe, fo);
- X}
- SHAR_EOF
- if test 12608 -ne "`wc -c < 'dconverse.c'`"
- then
- echo shar: "error transmitting 'dconverse.c'" '(should have been 12608 characters)'
- fi
- fi
- echo shar: "extracting 'misc.c'" '(4018 characters)'
- if test -f 'misc.c'
- then
- echo shar: "will not over-write existing file 'misc.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'misc.c'
- X
- X/*
- X** Miscellaneous support functions for smtp (borrowed from smail)
- X*/
- X
- X# include "smtp.h"
- X#ifdef BSD
- X# include <sys/timeb.h>
- X#endif
- X#ifdef SYSV
- X# include <sys/utsname.h>
- X#endif
- X
- Xchar hostdomain[256];
- Xchar hostname[256];
- X
- Xextern struct tm *localtime();
- X
- Xstruct tm *gmt, *loc; /* GMT and local time structure */
- Xtime_t now; /* current system time */
- Xchar nows[50]; /* time in ctime format */
- Xchar arpanows[50]; /* time in arpa format */
- X
- Xsetdates()
- X{
- X time_t time();
- X struct tm *gmtime();
- X char *ctime(), *arpadate();
- X
- X (void) time(&now);
- X (void) strcpy(nows, ctime(&now));
- X gmt = gmtime(&now);
- X loc = localtime(&now);
- X (void) strcpy(arpanows, arpadate(nows));
- X}
- X
- X/*
- X** Note: This routine was taken from sendmail
- X**
- X** ARPADATE -- Create date in ARPANET format
- X**
- X** Parameters:
- X** ud -- unix style date string. if NULL, one is created.
- X**
- X** Returns:
- X** pointer to an ARPANET date field
- X**
- X** Side Effects:
- X** none
- X**
- X** WARNING:
- X** date is stored in a local buffer -- subsequent
- X** calls will overwrite.
- X**
- X** Bugs:
- X** Timezone is computed from local time, rather than
- X** from whereever (and whenever) the message was sent.
- X** To do better is very hard.
- X**
- X** Some sites are now inserting the timezone into the
- X** local date. This routine should figure out what
- X** the format is and work appropriately.
- X*/
- X
- Xchar *
- Xarpadate(ud)
- X register char *ud;
- X{
- X register char *p;
- X register char *q;
- X static char b[40];
- X extern char *ctime();
- X register int i;
- X#ifndef BSD
- X extern char *tzname[];
- X extern long timezone;
- X char dspace[40];
- X time_t t, time();
- X int dst; /* dst active */
- X long tz;
- X#else
- X /* V7 and 4BSD */
- X struct timeb t;
- X extern struct timeb *ftime();
- X extern char *timezone();
- X#endif
- X
- X /*
- X ** Get current time.
- X ** This will be used if a null argument is passed and
- X ** to resolve the timezone.
- X */
- X
- X#ifndef BSD
- X (void) time(&t);
- X if (ud == NULL)
- X ud = ctime(&t);
- X#else
- X /* V7 or 4BSD */
- X ftime(&t);
- X if (ud == NULL)
- X ud = ctime(&t.time);
- X#endif
- X
- X /*
- X ** Crack the UNIX date line in a singularly unoriginal way.
- X */
- X
- X q = b;
- X
- X p = &ud[0]; /* Mon */
- X *q++ = *p++;
- X *q++ = *p++;
- X *q++ = *p++;
- X *q++ = ',';
- X *q++ = ' ';
- X
- X p = &ud[8]; /* 16 */
- X if (*p == ' ')
- X p++;
- X else
- X *q++ = *p++;
- X *q++ = *p++;
- X *q++ = ' ';
- X
- X p = &ud[4]; /* Sep */
- X *q++ = *p++;
- X *q++ = *p++;
- X *q++ = *p++;
- X *q++ = ' ';
- X
- X p = &ud[22]; /* 1979 */
- X *q++ = *p++;
- X *q++ = *p++;
- X *q++ = ' ';
- X
- X p = &ud[11]; /* 01:03:52 */
- X for (i = 8; i > 0; i--)
- X *q++ = *p++;
- X
- X /* -PST or -PDT */
- X#ifndef BSD
- X dst = localtime(&t)->tm_isdst;
- X tz = timezone - (dst ? 3600 : 0);
- X p = tzname[dst];
- X#else
- X p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
- X if (p[3] != '\0')
- X {
- X /* hours from GMT */
- X p += 3;
- X *q++ = *p++;
- X if (p[1] == ':')
- X *q++ = '0';
- X else
- X *q++ = *p++;
- X *q++ = *p++;
- X p++; /* skip ``:'' */
- X *q++ = *p++;
- X *q++ = *p++;
- X }
- X else
- X#endif
- X {
- X *q++ = ' ';
- X while (*p) *q++ = *p++;
- X }
- X#ifndef BSD
- X if (tz != 0) {
- X (void) sprintf (q, " (%c%02d%02d)",
- X ((tz > 0) ? '-' : '+'),
- X abs(tz/3600),
- X abs(tz%3600)/60);
- X q += strlen (q);
- X }
- X#endif
- X
- X *q = '\0';
- X return (b);
- X}
- X
- X/*
- X**
- X** getmynames(): what is my host name and host domain?
- X**
- X** Hostname set by -h, failing that by #define HOSTNAME, failing
- X** that by gethostname() or uname().
- X**
- X** Hostdomain set by -h, failing that by #define HOSTDOMAIN,
- X** failing that as hostname.MYDOM, or as just hostname.
- X**
- X** See defs.h for the inside story.
- X**
- X*/
- X
- Xgetmynames()
- X{
- X#ifdef HOSTNAME
- X if (!*hostname)
- X (void) strcpy(hostname, HOSTNAME);
- X#endif
- X#ifdef BSD
- X if (!*hostname)
- X gethostname(hostname, SMLBUF - 1);
- X#endif
- X#ifdef SYSV
- X if (!*hostname) {
- X struct utsname site;
- X
- X if (uname(&site) == 0)
- X (void) strcpy(hostname, site.nodename);
- X }
- X#endif
- X if (!*hostname)
- X return -1;
- X#ifdef HOSTDOMAIN
- X if (!*hostdomain)
- X (void) strcpy(hostdomain, HOSTDOMAIN);
- X#endif
- X#ifdef MYDOM
- X if (!*hostdomain)
- X (void) strcat(strcpy(hostdomain, hostname), MYDOM);
- X#endif
- X if (!*hostdomain)
- X (void) strcpy(hostdomain, hostname);
- X
- X return 1;
- X}
- SHAR_EOF
- if test 4018 -ne "`wc -c < 'misc.c'`"
- then
- echo shar: "error transmitting 'misc.c'" '(should have been 4018 characters)'
- fi
- fi
- echo shar: "extracting 'miscerrs.h'" '(197 characters)'
- if test -f 'miscerrs.h'
- then
- echo shar: "will not over-write existing file 'miscerrs.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'miscerrs.h'
- X/* these error numbers are local to the smtp programs, used by bomb() */
- X#define E_USAGE -1
- X#define E_NOHOST -2
- X#define E_CANTOPEN -3
- X#define E_OSFILE -4
- X#define E_IOERR -5
- X#define E_TEMPFAIL -6
- SHAR_EOF
- if test 197 -ne "`wc -c < 'miscerrs.h'`"
- then
- echo shar: "error transmitting 'miscerrs.h'" '(should have been 197 characters)'
- fi
- fi
- echo shar: "extracting 'mx.c'" '(5751 characters)'
- if test -f 'mx.c'
- then
- echo shar: "will not over-write existing file 'mx.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'mx.c'
- X#include <stdio.h>
- X#include <netdb.h>
- X#include <sysexits.h>
- X#include <sys/errno.h>
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <netinet/in.h>
- X#include <arpa/nameser.h>
- X#include "miscerrs.h"
- X
- X/* imports */
- Xextern int errno, h_errno;
- Xextern char *malloc(), *strcpy(), *inet_ntoa();
- X
- X/* exports */
- Xint mxconnect();
- X
- X/* private */
- X#define MAXMXLIST 10
- Xstatic struct mxitem {
- X char *host;
- X u_short pref;
- X u_char localflag;
- X} MXlist[MAXMXLIST + 1];
- Xstatic char *strsave();
- Xstatic int buildmxlist();
- Xstatic void mxsave(), mxinsert(), mxlocal();
- Xstatic struct hostent *getmxhost();
- X
- X#ifdef MXMAIN
- X
- X#define bomb return
- X
- Xmain(argc, argv)
- X char **argv;
- X{ int fd;
- X char buf[BUFSIZ], *crlf, *index();
- X struct mxitem *mxp;
- X
- X for (;;) {
- X printf("domain: ");
- X if (argc > 1)
- X strcpy(buf, argv[1]);
- X else if (gets(buf) == 0)
- X break;
- X if ((fd = mxconnect(buf)) >= 0)
- X if (read(fd, buf, 512) > 0) {
- X if ((crlf = index(buf, '\r')) != 0)
- X strcpy(crlf, "\n");
- X puts(buf);
- X } else
- X perror("read");
- X close(fd);
- X if (argc > 1)
- X break;
- X for (mxp = MXlist; mxp < MXlist + MAXMXLIST + 1; mxp++)
- X mxp->host = 0;
- X }
- X return 0;
- X}
- X#endif
- X
- Xmxconnect(host)
- X char *host;
- X{ int s, lport, mxfatal;
- X char **addr, errbuf[256];
- X struct hostent *hp;
- X struct servent *sp;
- X struct sockaddr_in sin;
- X struct mxitem *mxp;
- X
- X mxfatal = buildmxlist(host);
- X if (MXlist[0].host == 0)
- X MXlist[0].host = host;
- X if ((sp = getservbyname ("smtp", "tcp")) == NULL) {
- X (void)fprintf(stderr,"unknown service TCP/smtp\n");
- X bomb(E_OSFILE);
- X }
- X (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) 0, 0);
- X
- X /* slop in the loop -- i hate the socket dance */
- X for (mxp = MXlist; mxp->host; mxp++) {
- X if ((s = rresvport(&lport)) < 0) {
- X perror("rresvport");
- X bomb(E_CANTOPEN);
- X }
- X if ((hp = getmxhost(mxp->host)) == 0) {
- X (void) close(s);
- X if (mxfatal)
- X bomb(E_NOHOST);
- X continue;
- X }
- X bzero((char *)&sin, sizeof(sin));
- X sin.sin_port = sp->s_port;
- X sin.sin_family = hp->h_addrtype;
- X for (addr = hp->h_addr_list; *addr; addr++) {
- X bcopy(*addr, (char *) &sin.sin_addr, hp->h_length);
- X if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
- X sprintf(errbuf, "%s [%s]", mxp->host, inet_ntoa(sin.sin_addr));
- X perror(errbuf);
- X continue;
- X }
- X return s;
- X }
- X close(s);
- X }
- X
- X bomb(E_TEMPFAIL);
- X}
- X
- X/* return 1 for fatal MX error (authoritative NXDOMAIN), 0 o.w. */
- Xstatic int
- Xbuildmxlist(host)
- X char *host;
- X{ register HEADER *hp;
- X register char *cp;
- X register int n;
- X char q[PACKETSZ], a[PACKETSZ]; /* query, answer */
- X char *eom, *bp;
- X int buflen, ancount, qdcount;
- X char hostbuf[BUFSIZ+1];
- X u_short preference, reclen;
- X
- X if ((n = res_mkquery(QUERY, host, C_IN, T_MX, (char *) 0, 0, (struct rrec *) 0, q, sizeof(q))) < 0)
- X return 0;
- X n = res_send(q, n, a, sizeof(a));
- X if (n < 0)
- X return 0;
- X eom = a + n;
- X hp = (HEADER *) a;
- X ancount = ntohs(hp->ancount);
- X qdcount = ntohs(hp->qdcount);
- X if (hp->rcode != NOERROR || ancount == 0)
- X return hp->rcode == NXDOMAIN && hp->aa;
- X bp = hostbuf;
- X buflen = sizeof(hostbuf);
- X cp = a + sizeof(HEADER);
- X while (--qdcount >= 0)
- X cp += dn_skip(cp) + QFIXEDSZ;
- X /* TODO: if type is CNAME, reissue query */
- X while (--ancount >= 0 && cp < eom) {
- X cp += dn_skip(cp) /* name */
- X + sizeof(u_short) /* type */
- X + sizeof(u_short) /* class */
- X + sizeof(u_long); /* ttl (see rfc973) */
- X reclen = _getshort(cp);
- X cp += sizeof(u_short);
- X preference = _getshort(cp);
- X if ((n = dn_expand(a, eom, cp + sizeof(u_short), bp, buflen)) < 0)
- X break;
- X mxsave(bp, preference);
- X cp += reclen;
- X }
- X mxlocal();
- X return 0;
- X}
- X
- X/* NOT TODO: issue WKS query. (just try to connect.) */
- X
- Xstatic void
- Xmxsave(host, pref)
- X char *host;
- X u_short pref;
- X{ struct mxitem *mxp;
- X int localflag;
- X static char thishost[64];
- X
- X if (*thishost == 0)
- X gethostname(thishost, sizeof(thishost));
- X
- X if (MXlist[MAXMXLIST].host)
- X return; /* full */
- X
- X localflag = (strcmp(thishost, host) == 0);
- X
- X /* insertion sort */
- X for (mxp = MXlist; mxp < MXlist + MAXMXLIST; mxp++) {
- X if (mxp->host == 0) {
- X mxinsert(mxp, host, pref, localflag);
- X return;
- X }
- X if (pref < mxp->pref) {
- X mxinsert(mxp, host, pref, localflag);
- X return;
- X }
- X if (pref == mxp->pref) {
- X if (mxp->localflag)
- X return;
- X if (localflag) {
- X mxp->host = strsave(host);
- X mxp->pref = pref;
- X mxp->localflag = localflag;
- X (++mxp)->host = 0;
- X return;
- X }
- X mxinsert(mxp, host, pref, localflag);
- X return;
- X }
- X }
- X}
- X
- Xstatic void
- Xmxinsert(mxlistp, host, pref, localflag)
- X struct mxitem *mxlistp;
- X char *host;
- X u_short pref;
- X{ register struct mxitem *mxp;
- X
- X for (mxp = MXlist + MAXMXLIST - 1; mxp > mxlistp; --mxp)
- X *mxp = mxp[-1];
- X mxp->host = strsave(host);
- X mxp->pref = pref;
- X mxp->localflag = localflag;
- X}
- X
- Xstatic char *
- Xstrsave(str)
- X register char *str;
- X{ register char *rval;
- X
- X if ((rval = malloc(strlen(str) + 1)) == 0) {
- X perror("malloc");
- X bomb(-EX_SOFTWARE);
- X }
- X strcpy(rval, str);
- X return rval;
- X}
- X
- Xstatic void
- Xmxlocal()
- X{ register struct mxitem *mxp;
- X
- X if (MXlist[0].host == 0)
- X return;
- X
- X for (mxp = MXlist; mxp->host; mxp++) {
- X if (mxp->localflag) {
- X mxp->host = 0;
- X break;
- X }
- X }
- X}
- X
- Xstatic struct hostent *
- Xgetmxhost(host)
- X char *host;
- X{ struct hostent *hp, *gethostbyname();
- X
- X if ((hp = gethostbyname(host)) != 0)
- X return hp;
- X
- X switch(h_errno) {
- X
- X case HOST_NOT_FOUND:
- X (void) fprintf(stderr, "unknown host (%s).\n", host);
- X break;
- X
- X case TRY_AGAIN:
- X (void) fprintf(stderr, "name server not responding (%s).\n", host);
- X break;
- X
- X case NO_RECOVERY:
- X (void) fprintf(stderr, "name server error (%s).\n", host);
- X break;
- X
- X case NO_ADDRESS:
- X (void) fprintf(stderr, "no IP address (%s).\n", host);
- X break;
- X
- X default:
- X (void) fprintf(stderr, "unknown resolver error (%s).\n", host);
- X break;
- X }
- X return 0;
- X}
- SHAR_EOF
- if test 5751 -ne "`wc -c < 'mx.c'`"
- then
- echo shar: "error transmitting 'mx.c'" '(should have been 5751 characters)'
- fi
- fi
- echo shar: "extracting 'netio.c'" '(1442 characters)'
- if test -f 'netio.c'
- then
- echo shar: "will not over-write existing file 'netio.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'netio.c'
- X#ifndef lint
- Xstatic char *sccsid = "@(#)netio.c 1.7 87/07/31";
- X#endif lint
- X
- X#include "smtp.h"
- X#include <setjmp.h>
- X
- X#ifdef NOBOMB
- X#define bomb exit
- X#endif
- X
- Xchar *strcpy(), *strncat();
- X
- Xint hooting = 0; /* true if not server */
- X
- Xint
- Xtgets(line, size, fi) /* fgets from TCP */
- Xchar *line;
- Xint size;
- XFILE *fi;
- X{
- X register char *cr;
- X
- X *line = 0;
- X if (fgets(line, size, fi) == NULL)
- X return -1;
- X if (ferror(fi)) {
- X perror("error reading from smtp");
- X bomb(E_IOERR);
- X }
- X
- X /* convert \r\n -> \n */
- X cr = line + strlen(line) - 2;
- X if (cr >= line && *cr == '\r' && *(cr+1) == '\n') { /* CRLF there? */
- X *cr++ = '\n';
- X *cr = 0;
- X } else /* no CRLF present */
- X cr += 2; /* point at NUL byte */
- X
- X#ifdef HOOTING
- X if (hooting) (void) printf("<<< %s", line);
- X#endif
- X if (feof(fi)) {
- X perror("read eof from smtp");
- X bomb(E_IOERR);
- X }
- X return cr - line;
- X}
- X
- Xint
- Xtputs(line, fo) /* fputs to TCP */
- Xchar *line;
- XFILE *fo;
- X{
- X char buf[MAXSTR];
- X register char *nl;
- X extern int debug;
- X
- X (void) strcpy(buf, line);
- X#ifdef HOOTING
- X if (hooting) (void) printf(">>> %s", buf);
- X#endif
- X /* replace terminating \n by \r\n */
- X nl = buf + strlen(buf) - 1; /* presumably \n */
- X if (nl >= buf && *nl=='\n') { /* if it is ... */
- X *nl++ = '\r';
- X *nl++ = '\n';
- X *nl = 0;
- X } else
- X printf("unterminated line: <%s>\n", buf);
- X
- X (void) fputs(buf, fo);
- X (void) fflush(fo);
- X if (ferror(fo)) {
- X (void) perror("error writing to smtp");
- X bomb(E_IOERR);
- X }
- X return 0;
- X}
- SHAR_EOF
- if test 1442 -ne "`wc -c < 'netio.c'`"
- then
- echo shar: "error transmitting 'netio.c'" '(should have been 1442 characters)'
- fi
- fi
- echo shar: "extracting 'smtp.8'" '(4836 characters)'
- if test -f 'smtp.8'
- then
- echo shar: "will not over-write existing file 'smtp.8'"
- else
- sed 's/^X//' << \SHAR_EOF > 'smtp.8'
- X.TH SMTP 8 local "Public Domain"
- X.DA "4 May 1987"
- X.SH NAME
- Xsmtp, smtpd, in.smtpd \- SMTP talker and listeners
- X.br
- Xsmtpqer, runsmtpq, smtpq \- SMTP enqueuing, queue running and listing
- X.br
- Xcleansmtpq, returnsmtpmail \- SMTP queue cleaning and mail returning
- X.SH SYNOPSIS
- X.B /usr/lib/mail/smtp
- X[
- X.B \-h
- Xhelohost
- X]
- Xtargethost sender recipient
- X.br
- X.B "cd /usr/spool/smtpq; /usr/lib/mail/smtpd"
- X.br
- X.B "cd /usr/spool/smtpq; /usr/etc/in.smtpd"
- X.RB sourcehost . sourceport
- X.br
- X.B /usr/lib/mail/smtpqer
- X[
- X.B \-h
- Xhelohost
- X]
- Xtargethost sender recipient
- X.br
- X.B /usr/lib/mail/runsmtpq
- X.br
- X.B /usr/lib/mail/smtpq
- X.br
- X.B /usr/lib/mail/cleansmtpq
- X.br
- X.B /usr/lib/mail/returnsmtpmail
- X*.sh ...
- X.SH DESCRIPTION
- XThese routines provide a minimal stand-alone \s-2SMTP\s0 service.
- XIt consists of small programs that can be used with a central mail router like
- X.I upas,
- Xa system of your own construction,
- Xor
- X.IR sendmail .
- X.PP
- X.I smtp
- Xsends the mail message on its standard input to
- X.I targethost
- Xwhich in turn will deliver the message to
- X.I recipient
- Xas being from
- X.IR sender .
- X.I smtp
- Xcan be used with
- X.I sendmail
- Xinstead of the latter's built-in \s-2IPC\s0 mailer.
- XHere is a mailer definition we have used;
- Xyour mileage will vary:
- X.PP
- X.nf
- X.B
- XMether, P=/usr/lib/mail/smtp, F=SsDFuCX, S=11, R=21, A=smtp $h $g $u
- X.fi
- X.PP
- XEvery SMTP talker identifies itself in the
- X``host.domain''
- Xpart of the \s-2SMTP\s0 \s-2HELO\s0 message.
- XNormally
- X.I smtp
- Xuses the
- X.IR gethostname (2)
- Xcall to get the hostname,
- Xand the compiled-in DOMAINNAME,
- Xto identify itself.
- XThe
- X.B \-h
- Xoption allows you to override both values with one string,
- Xi.e.,
- X.BR \-h erewhon.peter.edu.
- XIf you are using
- X.I sendmail ,
- Xthen
- X.B \-h
- Xshould be added to the Mether definition with ``-h$j''
- X(but this has not yet been tested).
- XIn
- X.IR upas ,
- Xa typical rule is
- X.PP
- X.nf
- X.B
- X^([^!]+)\e.(mil|gov|edu|com|uk|org|net)!(.+)$ | "smtpqer -h \fIdom.ain\fP \e1.\e2 \es \e3"
- X.fi
- X.PP
- X.I smtpd
- Xis a 4.2BSD (or later) network daemon:
- Xit listens on the SMTP port
- X(TCP port 25 usually)
- Xfor an SMTP talker,
- Xreceives a mail message from it
- Xand hands the message to
- X.I cmail
- X(or equivalent other mail system).
- X.I in.smtpd
- Xis a similar 4.3BSD (or later)
- X.I inetd
- Xdaemon:
- Xit expects an SMTP connection on file descriptor zero (0)
- Xand the
- X.I sourcehost
- Xand
- X.I sourceport
- Xas its argument
- X.RI ( sourcehost
- Xin hexademical;
- X.I sourceport
- Xin decimal).
- X.PP
- X.I smtpqer
- Xqueues its standard input
- Xand shell commands to invoke
- X.I smtp
- Xwith
- X.IR smtpqer 's
- Xstandard input and arguments,
- Xand to remove the queued files if
- X.I smtp
- Xis successful.
- XIt then runs
- X.IR runsmtpq .
- X.PP
- X.I runsmtpq
- Xlocks the SMTP queue,
- Xexecutes all the shell command files in the SMTP queue,
- Xand unlocks the SMTP queue.
- X.I runsmtpq
- Xis stolen outright from the SM paper in the proceedings
- Xof the Portland Usenix conference.
- X.PP
- X.I smtpq
- Xshows the contents of the SMTP queue.
- X.PP
- X.I cleansmtpq
- Xreturns to sender mail which has been in the SMTP queue
- Xfor more than three days and removes it from the queue.
- X.PP
- X.I returnsmtpmail
- Xtakes the names of ``envelope'' shell files,
- Xreturns the messages therein
- Xand removes the messages from the SMTP queue.
- X.SH FILES
- X.BR /usr/spool/smtpq " the SMTP queue"
- X.br
- X.IB queue /*.sh
- X\& envelopes
- X.br
- X.IB queue /*.msg
- X\& message contents
- X.br
- X.IB queue /*.errs
- X\& errors from running
- X.I smtp
- X.br
- X.BR temp.* " incoming messages, created in"
- X.IR smtpd 's
- Xcurrent directory
- X.SH "SEE ALSO"
- XRFC 821 \- Simple Mail Transfer Protocol, ARPA Internet, NIC, SRI
- X.SH DIAGNOSTICS
- XBy default,
- Xthe talker program exits with the return codes defined in
- X.I <sysexits.h>
- Xfor
- X.IR sendmail .
- XTo disable this,
- Xcompile with -DNOSYSEXITS;
- Xit will exit with code 1 for all errors.
- X.SH HISTORY
- XThe SMTP talker (client) was written by Ian Darwin in 1985,
- Xas a simple telnet-like program
- Xthat just talked from stdin to a remote SMTP.
- XIn late 1986,
- Xit was built into a full talker
- Xwith some functions stolen
- Xfrom the public domain MIT UNIX TCP/IP implementation.
- X.PP
- XThe SMTP listener (daemon) was synthesised by Geoff Collyer
- Xby smashing together an old
- X.I nicname
- Xdaemon written by Ian with more public-domain SMTP code from MIT.
- X.PP
- X.I smtpqer
- Xand
- X.I smtpq
- Xwere written by Geoff Collyer.
- X.IR runsmtpq ,
- X.I cleansmtpq
- Xand
- X.I returnsmtpmail
- Xwere stolen from the SM Portland Usenix paper
- Xand adapted by Geoff Collyer.
- XPeter Honeyman installed it under
- X.I upas
- Xon the Internet and fixed a lot of bugs.
- XSome remain.
- X.SH BUGS
- XThe SMTP implementation is minimal,
- Xand could stand some fleshing out.
- X.PP
- X.I smtp
- Xand
- X.I smtpqer
- Xcould profitably handle multiple recipients on the same machine,
- Xbut dealing with bad recipients would be tricky.
- X.PP
- X.I smtpd
- Xand
- X.I in.smtpd
- Xcreate files named
- X.I temp.*
- Xin their current directories,
- Xso they should be run in the SMTP queue directory.
- X.PP
- X.I smtp
- Xand
- X.I smtpd
- Xlimit connect time to 30 minutes,
- Xwhich can be optimistic.
- SHAR_EOF
- if test 4836 -ne "`wc -c < 'smtp.8'`"
- then
- echo shar: "error transmitting 'smtp.8'" '(should have been 4836 characters)'
- fi
- fi
- echo shar: "extracting 'smtp.c'" '(4985 characters)'
- if test -f 'smtp.c'
- then
- echo shar: "will not over-write existing file 'smtp.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'smtp.c'
- X/*
- X * smtp -- client, send mail to remote smtp server
- X * Set up for 4.2BSD networking system.
- X * Adapted for System V by jv@mh.nl.
- X * TODO:
- X * better mapping of error numbers.
- X * allow multiple recipients (maybe)
- X * send stuff from cmds.h instead of hard-coded here
- X */
- X
- X#define USAGE "usage: %s [-h helohost] targethost sender recipient\n"
- X
- X#include "smtp.h"
- X#include <sys/uio.h> /* needed for socket.h */
- X#include <sys/socket.h>
- X#include <netinet/in.h>
- X#include <netdb.h>
- X
- X
- X#ifndef SERVNAME
- X#define SERVNAME "smtp" /* service we wanna talk to */
- X#endif
- X
- Xchar *progname;
- Xint debug = 0;
- Xextern char hostname[];
- Xextern char hostdomain[];
- Xchar *sendhost = hostdomain;
- XFILE *sfi, *sfo;
- Xchar *host = "None";
- Xchar *strcat(), *strcpy();
- Xstatic char *makedomain();
- X
- X#ifdef HOOTING
- Xextern int hooting; /* in netio */
- X#endif
- X
- X/*
- X * main - parse arguments and handle options
- X */
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X register int c;
- X int errflg = 0;
- X extern int optind;
- X extern char *optarg;
- X char *sender, *recip;
- X
- X progname = argv[0];
- X getmynames ();
- X
- X while ((c = getopt(argc, argv, "dh:")) != EOF)
- X switch (c) {
- X case 'd':
- X ++debug;
- X break;
- X case 'h': /* alternate sending host */
- X sendhost = optarg;
- X break;
- X case '?':
- X default:
- X errflg++;
- X break;
- X }
- X if (errflg || (argc - optind) < 3) {
- X (void) fprintf(stderr, USAGE, progname);
- X bomb(E_USAGE);
- X }
- X host = argv[optind++];
- X sender = makedomain(argv[optind++], sendhost);
- X recip = makedomain(argv[optind++], host);
- X
- X setup(); /* open connection */
- X
- X
- X#ifdef HOOTING
- X hooting = 1;
- X#endif
- X /* hold the conversation */
- X
- X converse(sender, recip, sfi, sfo, stdin);
- X (void) sleep(5); /* drain? */
- X
- X if (sfo!=NULL)
- X (void) fclose(sfo);
- X if (sfi!=NULL)
- X (void) fclose(sfi);
- X
- X return 0;
- X}
- X
- X/*
- X * setup -- setup tcp/ip connection to/from server
- X */
- Xsetup()
- X{
- X struct hostent *hp;
- X struct servent *sp;
- X struct sockaddr_in sin;
- X int s;
- X extern int errno;
- X
- X (void) bzero((char *)&sin, sizeof(sin));
- X
- X if ((hp = gethostbyname(host)) == (struct hostent *) NULL) {
- X (void) fprintf(stderr, "unknown host (%s).\n", host);
- X bomb(E_NOHOST);
- X }
- X
- X (void) bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
- X
- X if ((sp = getservbyname (SERVNAME, "tcp")) == NULL) {
- X (void)fprintf(stderr,"unknown service TCP/%s\n", SERVNAME);
- X bomb(E_OSFILE);
- X }
- X sin.sin_port = sp->s_port;
- X sin.sin_family = hp->h_addrtype;
- X
- X if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
- X perror("setup - socket");
- X bomb(E_CANTOPEN);
- X }
- X
- X if (connect(s, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
- X perror("setup - connect");
- X /*
- X * check for conditions that (we think) are temporary;
- X * try them later; bomb utterly on all others.
- X */
- X if (errno == ETIMEDOUT || errno == ECONNREFUSED ||
- X errno == EHOSTDOWN || errno == EHOSTUNREACH)
- X bomb(E_TEMPFAIL);
- X else
- X bomb(E_CANTOPEN);
- X }
- X
- X if (((sfi = fdopen(s, "r")) == (FILE *) NULL) ||
- X ((sfo = fdopen(s, "w")) == (FILE *) NULL)) {
- X perror("setup - fdopen");
- X bomb(E_CANTOPEN);
- X }
- X/* setbuf(sfi, (char *) 0);*/
- X}
- X
- X/*
- X * bomb(code) - exit program, map smtp error code into mailsystem code
- X * Codes with E_ are defined in miscerrs.h.
- X * Codes with EX_ are from <sysexits.h>
- X * Lines with FOO are placeholders until we decrypt more appropriate codes.
- X */
- Xbomb(code)
- Xint code;
- X{
- X if (sfi != NULL)
- X (void) fclose(sfi);
- X if (sfo != NULL)
- X (void) fclose(sfo);
- X
- X#ifdef EX_OK
- X switch(code) {
- X case 451: /* host not responding */
- X code = EX_UNAVAILABLE; /* service unavailable */
- X break;
- X case 550:
- X code = EX_NOUSER; /* addressee unknown */
- X break;
- X case 501: /* syntax error in address */
- X case 554: /* */
- X code = EX_DATAERR; /* data format error */
- X break;
- X case E_IOERR:
- X code = EX_IOERR; /* input/output error */
- X break;
- X case E_NOHOST:
- X code = EX_NOHOST; /* host name unknown */
- X break;
- X case E_OSFILE: /* no "smtp" -> /etc/services f'd */
- X code = EX_OSFILE; /* critical OS file missing */
- X break;
- X case E_USAGE:
- X code = EX_USAGE; /* command line usage error */
- X break;
- X case E_TEMPFAIL:
- X code = EX_TEMPFAIL; /* temp failure; user can retry */
- X break;
- X#if 0
- X case FOO:
- X code = EX_OSERR; /* system error (e.g., can't fork) */
- X break;
- X case FOO:
- X code = EX_NOINPUT; /* cannot open input */
- X break;
- X case FOO:
- X code = EX_CANTCREAT; /* can't create (user) output file */
- X break;
- X case FOO:
- X code = EX_PROTOCOL; /* remote error in protocol */
- X break;
- X case FOO:
- X code = EX_NOPERM; /* permission denied */
- X break;
- X#endif /* NOTDEF */
- X default: /* can't happen? */
- X code = EX_SOFTWARE; /* internal software error */
- X break;
- X }
- X
- X#else /* has no sysexits */
- X code = 1;
- X#endif
- X
- X (void) exit (code);
- X}
- X
- Xstatic char *
- Xmakedomain(addr, domain)
- Xchar *addr, *domain;
- X{
- X char *rval;
- X extern char *index(), *malloc();
- X
- X if (index(addr, '@') != 0)
- X return addr;
- X
- X if ((rval = malloc(strlen(addr) + strlen(domain) + 2)) == 0)
- X#ifdef EX_SOFTWARE
- X bomb(EX_SOFTWARE); /* can't happen! */
- X#else
- X bomb (3);
- X#endif
- X sprintf(rval, "%s@%s", addr, domain);
- X return rval;
- X}
- SHAR_EOF
- if test 4985 -ne "`wc -c < 'smtp.c'`"
- then
- echo shar: "error transmitting 'smtp.c'" '(should have been 4985 characters)'
- fi
- fi
- echo shar: "extracting 'smtp.h'" '(1022 characters)'
- if test -f 'smtp.h'
- then
- echo shar: "will not over-write existing file 'smtp.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'smtp.h'
- X/* smtp.h */
- X
- X#include "config.h"
- X
- X/* smtp constants and the like */
- X
- X/* tunable constants */
- X#define MAXSTR 10240 /* maximum string length */
- X#define NAMSIZ MAXSTR /* max file name length */
- X
- X/* standard includes and portability */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <sys/types.h>
- X#include <errno.h>
- X#include "miscerrs.h"
- X
- X#ifdef BSD
- X#include <strings.h>
- X#include <sys/time.h>
- X#include <sys/wait.h>
- Xextern char *sprintf();
- X# ifndef NOSYSEXITS
- X# include <sysexits.h>
- X# endif
- X#endif
- X
- X#ifdef SYSV
- X#include <string.h>
- X#include <time.h>
- X#include <fcntl.h>
- X#define index strchr
- X#define rindex strrchr
- X#define bcopy(a,b,n) memcpy(b,a,n)
- X#define bzero(a,n) memset(a,'\0',n)
- X#define SIGCHLD SIGCLD
- Xextern int sprintf();
- X# ifndef NOSYSEXITS
- X# include "sysexits.h"
- X# endif
- X#endif
- X
- X#ifndef EX_SOFTWARE
- X# define EX_SOFTWARE 70 /* internal software error */
- X#endif
- X
- X#ifdef SYSLOG
- X# ifdef SYSV
- X# include "syslog.h"
- X# else
- X# include <syslog.h>
- X# endif
- X#endif
- X
- X#ifndef TRUE
- X# define TRUE 1
- X# define FALSE 0
- X#endif
- SHAR_EOF
- if test 1022 -ne "`wc -c < 'smtp.h'`"
- then
- echo shar: "error transmitting 'smtp.h'" '(should have been 1022 characters)'
- fi
- fi
- echo shar: "extracting 'smtpd.c'" '(5297 characters)'
- if test -f 'smtpd.c'
- then
- echo shar: "will not over-write existing file 'smtpd.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'smtpd.c'
- X#ifndef lint
- Xstatic char *sccsid = "@(#)smtpd.c 1.7 87/07/31";
- X#endif lint
- X/*
- X * smtpd - SMTP listener: receives SMTP mail & invokes cmail.
- X * SMTP is either Simple Mail Transfer Protocol or
- X * Sado-Masochistic Torture Procedure.
- X */
- X
- X#include "smtp.h"
- X#include <signal.h>
- X#include <netdb.h>
- X#include <sys/uio.h>
- X#include <sys/socket.h>
- X#ifdef BSD
- X#include <sgtty.h>
- X#include <sys/wait.h>
- X#endif
- X#include <sys/resource.h> /* for wait3(2) */
- X#include <netinet/in.h>
- X
- X/* forward declarations */
- XFILE *popen();
- X
- X#ifdef INETD
- X#ifdef BSD
- Xint reapchild();
- X#endif
- X#endif
- X
- Xextern char **environ;
- Xextern int errno, sys_nerr;
- Xextern char *sys_errlist[];
- X
- X#ifndef SERVNAME
- X#define SERVNAME "smtp"
- X#endif /* SERVNAME */
- Xstruct sockaddr_in sin = { AF_INET };
- Xstruct sockaddr_in from;
- X
- Xint debug;
- Xchar *progname;
- Xchar logm[MAXSTR];
- X
- X/*
- X * main - parse arguments and handle options
- X */
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X int c;
- X int errflg = 0;
- X extern int optind;
- X extern char *optarg;
- X
- X progname = argv[0];
- X getmynames ();
- X
- X while ((c = getopt(argc, argv, "d")) != EOF)
- X switch (c) {
- X case 'd':
- X ++debug;
- X break;
- X case '?':
- X default:
- X errflg++;
- X break;
- X }
- X if (errflg) {
- X logit(LOG_CRIT, "Usage: %s [-d]\n", progname);
- X exit(2);
- X }
- X
- X if (optind >= argc)
- X process();
- X#ifdef INETD
- X else if (optind == argc - 1) { /* one argument */
- X if (sscanf(argv[optind], "%lx.%hd", &from.sin_addr.s_addr,
- X &from.sin_port) != 2) {
- X logit(LOG_CRIT,
- X "in.smtpd: bad arg from inetd: %s\n",
- X argv[optind]);
- X exit(2);
- X }
- X from.sin_family = AF_INET;
- X from.sin_addr.s_addr = htonl(from.sin_addr.s_addr);
- X from.sin_port = htons(from.sin_port);
- X process();
- X }
- X#endif /* INETD */
- X else {
- X logit(LOG_CRIT, "%s: too many args\n", progname);
- X exit(2);
- X }
- X
- X return 0;
- X}
- X
- X/*
- X * process - process input file
- X */
- Xprocess()
- X{
- X#ifndef INETD
- X int s, pid;
- X#endif /* INETD */
- X struct servent *sp;
- X
- X sp = getservbyname(SERVNAME, "tcp");
- X if (sp == 0) {
- X logit(LOG_CRIT, "tcp/%s: unknown service\n", SERVNAME);
- X exit(1);
- X }
- X sin.sin_port = sp->s_port;
- X
- X#ifdef INETD
- X /* connection on fd 0 from inetd */
- X doit(0, &from);
- X /* NOTREACHED */
- X exit(0);
- X#else /* INETD */
- X#ifndef DEBUG
- X if (fork()) /* run in the background */
- X exit(0);
- X for (s = 0; s < 10; s++) /* close most file descriptors */
- X (void) close(s);
- X (void) open("/dev/null", 0); /* reopen them on harmless streams */
- X (void) dup2(0, 1);
- X (void) dup2(0, 2);
- X { int tt = open("/dev/tty", 2); /* leave current process group */
- X if (tt > 0) {
- X#ifdef TIOCNOTTY
- X (void) ioctl(tt, TIOCNOTTY, (char *)0);
- X#endif
- X (void) close(tt);
- X }
- X }
- X#endif /* DEBUG */
- X /* create internet socket s; retry 5 times at 5 s. intervals if no luck */
- X while ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- X static int nlog = 0;
- X
- X if (nlog++ <= 5)
- X logit(LOG_CRIT, "socket", "");
- X sleep(5);
- X }
- X /* set socket options, notably keepalive */
- X if (debug) {
- X int debugval = 1;
- X
- X if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
- X (char *)&debugval, sizeof(int)) < 0)
- X logit(LOG_CRIT, "setsockopt (SO_DEBUG)", "");
- X }
- X if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)0, 0) < 0)
- X logit(LOG_CRIT, "setsockopt (SO_KEEPALIVE)", "");
- X /* bind socket to SERVNAME (SMTP) port; retry as above on failure */
- X while (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
- X static int nlog = 0;
- X
- X if (nlog++ <= 5)
- X logit(LOG_CRIT, "bind", "");
- X sleep(5);
- X }
- X
- X#ifdef BSD
- X (void) signal(SIGCHLD, TYPESIG reapchild);
- X#else
- X (void) signal(SIGCHLD, SIG_IGN); /* SystemV takes care ... */
- X#endif
- X
- X /* listen with 10 input buffers on socket (?) */
- X if (listen(s, 10) == -1)
- X logit(LOG_CRIT, "listen", "");
- X for (;;) {
- X int conn, fromlen = sizeof from;
- X
- X /* get a connection on fd conn; stores src host addr in from */
- X conn = accept(s, (struct sockaddr *)&from, &fromlen);
- X if (conn < 0) {
- X static int nlog = 0;
- X
- X if (errno == EINTR)
- X continue;
- X if (++nlog <= 5)
- X logit(LOG_CRIT, "accept", "");
- X sleep(1);
- X continue;
- X }
- X /* fork a child for this connection */
- X if ((pid = fork()) < 0)
- X logit(LOG_CRIT, "can't fork!!", "");
- X else if (pid == 0) {
- X (void) signal(SIGCHLD, SIG_DFL);
- X doit(conn, &from); /* listen to SMTP dialogue */
- X /* NOTREACHED */
- X exit(0);
- X }
- X (void) close(conn);
- X }
- X /*NOTREACHED*/
- X#endif /* INETD */
- X}
- X
- X#ifndef INETD
- X#ifdef BSD
- Xreapchild()
- X{
- X union wait status;
- X
- X /* gross hack! */
- X while (wait3(&status, WNOHANG, (struct rusage *)0) > 0);
- X
- X}
- X#endif /* BSD */
- X#endif /* INETD */
- X
- X/*
- X * handle some input. never returns.
- X */
- Xdoit(f, fromaddr)
- Xint f;
- Xstruct sockaddr_in *fromaddr; /* internet addr of sending host */
- X{
- X FILE *fi, *fo;
- X
- X if ((fi = fdopen(f, "r")) == NULL)
- X logit(LOG_CRIT, "fdopen of socket for input", "");
- X if ((fo = fdopen(f, "w")) == NULL)
- X logit(LOG_CRIT, "fdopen of socket for output", "");
- X
- X converse(fi, fo, fromaddr);
- X /* NOTREACHED */
- X return 0;
- X}
- X
- X#ifndef NOBOMB
- Xbomb(err)
- Xint err;
- X{
- X death(err);
- X}
- X#endif
- X
- Xlogit (sev, fmt, str)
- Xint sev;
- Xchar *fmt, *str;
- X{
- X#ifdef SYSLOG
- X (void) sprintf(logm, "%s: %s", progname, fmt);
- X (void) syslog(sev, logm, (str == "" && errno <= sys_nerr)?
- X sys_errlist[errno]: str);
- X#else
- X (void) sprintf(logm, "%s: %s", progname, fmt);
- X (void) fprintf(stderr, logm, (str == "" && errno <= sys_nerr)?
- X sys_errlist[errno]: str);
- X#endif
- X}
- SHAR_EOF
- if test 5297 -ne "`wc -c < 'smtpd.c'`"
- then
- echo shar: "error transmitting 'smtpd.c'" '(should have been 5297 characters)'
- fi
- fi
- echo shar: "extracting 'sysexits.h'" '(3662 characters)'
- if test -f 'sysexits.h'
- then
- echo shar: "will not over-write existing file 'sysexits.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'sysexits.h'
- X/*
- X** SYSEXITS.H -- Exit status codes for system programs.
- X**
- X** This include file attempts to categorize possible error
- X** exit statuses for system programs, notably delivermail
- X** and the Berkeley network.
- X**
- X** Error numbers begin at EX__BASE to reduce the possibility of
- X** clashing with other exit statuses that random programs may
- X** already return. The meaning of the codes is approximately
- X** as follows:
- X**
- X** EX_USAGE -- The command was used incorrectly, e.g., with
- X** the wrong number of arguments, a bad flag, a bad
- X** syntax in a parameter, or whatever.
- X** EX_DATAERR -- The input data was incorrect in some way.
- X** This should only be used for user's data & not
- X** system files.
- X** EX_NOINPUT -- An input file (not a system file) did not
- X** exist or was not readable. This could also include
- X** errors like "No message" to a mailer (if it cared
- X** to catch it).
- X** EX_NOUSER -- The user specified did not exist. This might
- X** be used for mail addresses or remote logins.
- X** EX_NOHOST -- The host specified did not exist. This is used
- X** in mail addresses or network requests.
- X** EX_UNAVAILABLE -- A service is unavailable. This can occur
- X** if a support program or file does not exist. This
- X** can also be used as a catchall message when something
- X** you wanted to do doesn't work, but you don't know
- X** why.
- X** EX_SOFTWARE -- An internal software error has been detected.
- X** This should be limited to non-operating system related
- X** errors as possible.
- X** EX_OSERR -- An operating system error has been detected.
- X** This is intended to be used for such things as "cannot
- X** fork", "cannot create pipe", or the like. It includes
- X** things like getuid returning a user that does not
- X** exist in the passwd file.
- X** EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
- X** etc.) does not exist, cannot be opened, or has some
- X** sort of error (e.g., syntax error).
- X** EX_CANTCREAT -- A (user specified) output file cannot be
- X** created.
- X** EX_IOERR -- An error occurred while doing I/O on some file.
- X** EX_TEMPFAIL -- temporary failure, indicating something that
- X** is not really an error. In sendmail, this means
- X** that a mailer (e.g.) could not create a connection,
- X** and the request should be reattempted later.
- X** EX_PROTOCOL -- the remote system returned something that
- X** was "not possible" during a protocol exchange.
- X** EX_NOPERM -- You did not have sufficient permission to
- X** perform the operation. This is not intended for
- X** file system problems, which should use NOINPUT or
- X** CANTCREAT, but rather for higher level permissions.
- X** For example, kre uses this to restrict who students
- X** can send mail to.
- X**
- X** Maintained by Eric Allman (eric@berkeley, ucbvax!eric) --
- X** please mail changes to me.
- X**
- X** @(#)sysexits.h 1.2 86/05/09 ACE (c)
- X*/
- X
- X# define EX_OK 0 /* successful termination */
- X
- X# define EX__BASE 64 /* base value for error messages */
- X
- X# define EX_USAGE 64 /* command line usage error */
- X# define EX_DATAERR 65 /* data format error */
- X# define EX_NOINPUT 66 /* cannot open input */
- X# define EX_NOUSER 67 /* addressee unknown */
- X# define EX_NOHOST 68 /* host name unknown */
- X# define EX_UNAVAILABLE 69 /* service unavailable */
- X# define EX_SOFTWARE 70 /* internal software error */
- X# define EX_OSERR 71 /* system error (e.g., can't fork) */
- X# define EX_OSFILE 72 /* critical OS file missing */
- X# define EX_CANTCREAT 73 /* can't create (user) output file */
- X# define EX_IOERR 74 /* input/output error */
- X# define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
- X# define EX_PROTOCOL 76 /* remote error in protocol */
- X# define EX_NOPERM 77 /* permission denied */
- SHAR_EOF
- if test 3662 -ne "`wc -c < 'sysexits.h'`"
- then
- echo shar: "error transmitting 'sysexits.h'" '(should have been 3662 characters)'
- fi
- fi
- echo shar: "extracting 'syslog.h'" '(24 characters)'
- if test -f 'syslog.h'
- then
- echo shar: "will not over-write existing file 'syslog.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'syslog.h'
- X#include <sys/syslog.h>
- SHAR_EOF
- if test 24 -ne "`wc -c < 'syslog.h'`"
- then
- echo shar: "error transmitting 'syslog.h'" '(should have been 24 characters)'
- fi
- fi
- echo shar: "extracting 'MANIFEST'" '(144 characters)'
- if test -f 'MANIFEST'
- then
- echo shar: "will not over-write existing file 'MANIFEST'"
- else
- sed 's/^X//' << \SHAR_EOF > 'MANIFEST'
- XMakefile
- XREADME
- Xcmds.h
- Xconfig.h
- Xconverse.c
- Xdconverse.c
- Xmisc.c
- Xmiscerrs.h
- Xmx.c
- Xnetio.c
- Xsmtp.8
- Xsmtp.c
- Xsmtp.h
- Xsmtpd.c
- Xsysexits.h
- Xsyslog.h
- XMANIFEST
- SHAR_EOF
- if test 144 -ne "`wc -c < 'MANIFEST'`"
- then
- echo shar: "error transmitting 'MANIFEST'" '(should have been 144 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-
- --
- postmaster on node mhres (currently: Johan Vromans)
-